import 'dart:async';
import 'dart:io';
import 'dart:convert';

typedef HandleFunc = Future<void> Function(HttpRequest, DeferFuncs);
typedef MiddleWare = Future<MiddleWareStatus> Function(HttpRequest, DeferFuncs);
typedef MiddleWareStatus = bool;
const MiddleWareStatus NEXT = true;
const MiddleWareStatus STOP = false;

class LxRouter {
  LxServer server;
  String pre_path;
  LxRouter(this.server, {this.pre_path = '/'});
  LxRouter group(String schema) {
    return LxRouter(server, pre_path: pre_path + schema + '/');
  }

  void get(String schema, HandleFunc f) {
    server.m_to_f_get[pre_path + schema] = f;
    return;
  }

  void post(String schema, HandleFunc f) {
    server.m_to_f_post[pre_path + schema] = f;
    return;
  }
}

enum JobType {
  target, //特定时间任务
  period, //周期任务
}

class CronJob {
  // late Enum type; //任务类别
  // late DateTime startTime; //任务开始时间
  // late DateTime endTime; //任务结束时间
  // late Duration period;
  // late int finishCount=0;//任务完成次数
  // late int count; //任务重复次数
  late bool Function() f; //任务
  late DateTime trigerTime; //触发时机(分钟触发)
  DateTime lastTrigerTime = DateTime(2018); //上一次触发时机
  CronJob({required this.trigerTime, required this.f});
  void doJob() {
    // print('定时任务触发：${DateTime.now()}');
    //一天触发一次
    if (lastTrigerTime.difference(DateTime.now()).inDays == 0) {
      return;
    }

    //对应时间触发
    if (DateTime.now().hour == trigerTime.hour &&
        DateTime.now().minute == trigerTime.minute) {
      var flag = f();
      if (flag) {
        //执行成功修改上次触发时机
        lastTrigerTime = DateTime.now();
      }
    }
    return;
  }
}

class DeferFuncs {
  List<void Function()> funcs = [];
  void add(void Function() f) {
    funcs.add(f);
  }

  void deal() {
    for (var deferFunc in funcs) {
      deferFunc();
    }
  }
}

class LxServer {
  String ip;
  int port;
  String domain;
  late Map<String, HandleFunc> m_to_f_get;
  late Map<String, HandleFunc> m_to_f_post;
  late List<CronJob> cronJobs;
  late List<MiddleWare> middleWares;
  LxServer(
      {this.ip = '0.0.0.0', this.port = 10086, this.domain = '127.0.0.1'}) {
    m_to_f_get = {};
    m_to_f_post = {};
    cronJobs = [];
    middleWares = [];
  }

  //注册路由后启动，完成跨域配置，异步处理每个请求
  void serve() async {
    var requestServer = await HttpServer.bind(ip, port);
    print('http服务已启动,监听ip：$ip,端口：$port');
    m_to_f_get.forEach((key, value) {
      print('GET    http://$domain:$port$key  func：${value.toString()}');
    });

    m_to_f_post.forEach((key, value) {
      print('POST    http://$domain:$port$key  func：${value.toString()}');
    });

    Timer.periodic(Duration(seconds: 5), (timer) {
      for (var job in cronJobs) {
        job.doJob();
      }
    });

    await for (HttpRequest req in requestServer) {
      print(
          'request  ${req.method}  ${req.uri.path},params:${req.uri.queryParameters}');
      try {
        var path = req.requestedUri.path;
        var method = req.method;
        var f;
        var deferFuncs = DeferFuncs();
        if (method == 'GET') {
          f = m_to_f_get[path];
        } else if (method == 'POST') {
          f = m_to_f_post[path];
        }

        var flag = NEXT;
        for (var middleWare in middleWares) {
          var middleWareDeferFuns = DeferFuncs();
          flag = await middleWare(req, middleWareDeferFuns);
          middleWareDeferFuns.deal();
          if (flag == STOP) {
            await req.response.close();
            break;
          }
        }
        if (flag == STOP) {
          continue;
        }

        if (f == null) {
          req.response
            ..write(jsonEncode({'msg': '请检查路径是否正确', 'code': '5001'}))
            ..close();
          continue;
        }

        await f(req, deferFuncs);
        deferFuncs.deal(); //业务逻辑执行后的延迟函数，比如释放数据库连接等
      } catch (e) {
        print(e);
        safeResponse(jsonEncode({'msg': '系统开小差了', 'code': '5001'}), req);
      }
    }
  }

  void registeCronJob({
    required int hour,
    required int minute,
    required bool Function() job,
  }) {
    cronJobs
        .add(CronJob(trigerTime: DateTime(2018, 6, 18, hour, minute), f: job));
  }

  void use(MiddleWare m) {
    middleWares.add(m);
  }

  //获取路由，进行路由配置
  LxRouter getRouter() {
    return LxRouter(this);
  }
}

void safeResponse(var msg, HttpRequest req, {String code = '0'}) {
  try {
    req.response
      ..write(jsonEncode({'msg': msg, 'code': code}))
      ..close();
  } catch (e) {
    req.response.close();
  }
}
